package de.graph.common.impl;

import java.util.Collection;

import de.graph.common.Edge;
import de.graph.common.Graph;
import de.graph.common.Vertex;
import de.graph.common.impl.GraphFactory.GraphType;
import de.graph.document.Document;

final class GraphImpl implements Graph {

	protected final Document graphDocument;
    
    protected GraphImpl(final Document graphDocument) {
        this.graphDocument  = graphDocument; 
	}

	@Override
	public Vertex createVertex() {
        Vertex vertex = VertexFactory.create();
        
        getVertexSet().add(vertex);
        
        return vertex;
	}

	@Override
	public Vertex createVertex(String label) {

		Vertex vertex = VertexFactory.create(label);
		
        getVertexSet().add(vertex);
        
        return vertex;
	}

	@Override
	public void removeVertex(Vertex vertex) {
		getVertexSet().remove(vertex);
	}

	@Override
	public Collection<Vertex> getVertices() {
		return getVertexSet();
	}

    @Override
    public Collection<Vertex> getVertices(String label) {
        // TODO 
        return getVertexSet();
    }

	@Override
	public Edge createEdge(Vertex source, Vertex target) {
		return createEdge(source, target, null);
	}

	@Override
	public Edge createEdge(Vertex source, Vertex target, String label) {
		if (source == null) {
			throw new IllegalArgumentException("Parameter 'source' must not be null!");
		}
		
		if (target == null) {
			throw new IllegalArgumentException("Parameter 'target' must not be null!");
		}
		
		Edge edge = EdgeFactory.create(source, target, isDirected(), label);
		
		source.getOutEdges().add(edge);
		target.getInEdges().add(edge);

		if (!isDirected()) {
			target.getOutEdges().add(edge);
			source.getInEdges().add(edge);
		}
		
		getEdgeSet().add(edge);
		
		return edge;
	}

	@Override
	public void removeEdge(Edge edge) {
		edge.getSourceVertex().getOutEdges().remove(edge);
		edge.getTargetVertex().getInEdges().remove(edge);
		
		if (!isDirected()) {
			edge.getTargetVertex().getOutEdges().remove(edge);
			edge.getSourceVertex().getInEdges().remove(edge);
		}
		
		getEdgeSet().remove(edge);
	}

	@Override
	public Collection<Edge> getEdges() {
		return getEdgeSet();
	}

	@Override
	public Collection<Edge> getEdges(String label) {
		// TODO 
		return getEdgeSet();
	}

	@Override
    public boolean isDirected() {
        return (getGraphDocument().getProperty(GraphFactory.GRAPH_TYPE) == GraphType.DIRECTED);
    }

	@Override
	public void clear() {
	    for (Vertex vertex : getVertices()) {
	        ((ElementImpl)vertex).getDocument().clear();
        }	    
	    getVertexSet().clear();
	    
        for (Edge edge : getEdges()) {
            ((ElementImpl)edge).getDocument().clear();
        }        
	    getEdgeSet().clear();
	    
	    getGraphDocument().clear();
	}
	
	private Collection<Vertex> getVertexSet() {
        return getGraphDocument().getProperty(GraphFactory.VERTEX_SET);
    }
	
	private Collection<Edge> getEdgeSet() {
        return getGraphDocument().getProperty(GraphFactory.EDGE_SET);
    }
    
    private Document getGraphDocument() {
        return graphDocument;
    }
}
